<!DOCTYPE html>
<html>
<head>
<title>List General Tests</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-git.css" type="text/css" />
<script src="http://code.jquery.com/qunit/qunit-git.js"></script>
<script src="qunit/connector.js"></script>
<script type="text/javascript" src="qunit/runner.js"></script>
<script type="text/javascript" src="js/utils.js"></script>
<script type="text/javascript" src="js/tiny_mce_loader.js"></script>
<script type="text/javascript" src="js/dsl/dsl.js"></script>
<script>
QUnit.config.reorder = false;
QUnit.config.autostart = false;

var ENTER = 0xA;
var TAB = 0x9;
var BACKSPACE = 0x8;
var ZERO_SIZED_NBSP = "\uFEFF";
var LEFT = 0x26;

module('Lists - General', {
	autostart: false,
	setup: function() {
		window.queue = new dsl.Queue();
	}
});

// Tests
asyncTest('Escape unordered list by pressing enter on last empty li', function() {
	editor.setContent("");
	editor.execCommand('InsertUnorderedList');
	robot.type('a', false, function(){
		robot.type(ENTER, false, function(){
			robot.type(ENTER, false, function() {
				var node = editor.selection.getNode();
				var list = editor.dom.getParent(node, 'ol,ul');
				equal(editor.dom.select('li').length, 1);
				ok(list === null, "selection must be outside of list");
				start();
			}, editor.selection.getNode());
		}, editor.selection.getNode());
	}, editor.selection.getNode());
});

asyncTest('Escape ordered list by pressing enter on last empty li', function() {
	editor.setContent("");
	editor.execCommand('InsertOrderedList');
	robot.type('a', false, function() {
		robot.type(ENTER, false, function() {
			robot.type(ENTER, false, function() {
				var node = editor.selection.getNode();
				var list = editor.dom.getParent(node, 'ol,ul');
				equal(editor.dom.select('li').length, 1);
				ok(list === null, "selection must be outside of list");
				start();
			}, editor.selection.getNode());
		}, editor.selection.getNode());
	}, editor.selection.getNode());
});

asyncTest('Escaping list and applying style only applies styles to new text', function() {
	editor.setContent("<ul><li>abc</li><li>def</li><li></li></ul>");
	setSelection("ul li:nth-child(3)", 0);
	robot.type(ENTER, false, function() {
		robot.type('a', false, function() {
			editor.execCommand('FormatBlock', false, 'h1');
			equal(editor.getContent(), "<ul><li>abc</li><li>def</li></ul><h1>a</h1>");
			start();
		}, editor.selection.getNode());
	}, editor.selection.getNode());
});

asyncTest('Caret positioned correctly after outdenting on non-last empty li', function() {
	editor.setContent("<ul><li>a</li><li id='a'></li><li id>b</li></ul>");
	setSelection("#a", 0);
	robot.type(TAB, true, function() {
		var tagName = editor.selection.getNode().tagName;
		equal('P', tagName);
		start();
	}, editor.selection.getNode());
});

asyncTest('Caret position correctly after pressing enter on li with text', function() {
	editor.setContent("<ol><li>a<ol><li>b</li><li></li></ol></li></ol>");
	setSelection('li ol li:nth-child(2)', 0);
	robot.type(ENTER, false, function(){
		var node = editor.selection.getNode();
		equal(editor.getContent(), "<ol><li>a<ol><li>b</li></ol></li></ol>");
		equal(node.parentNode.lastChild, node);
		start();
	}, editor.selection.getNode());
});

asyncTest('Caret positioned correctly after pressing enter multiple times to exit list', function() {
	editor.focus();
	editor.setContent("<ul><li>a</li><li>b</li></ul><p id='last'>some text</p>");
	setSelection('ul li:nth-child(2)', 1);
	
	robot.type(ENTER, false, function(){
		robot.type(ENTER, false, function(){
			robot.type(ENTER, false, function(){
				var node = editor.dom.getParent(editor.selection.getNode(), editor.dom.isBlock);

				equal(node.tagName, 'P');
				equal(node.nextSibling.tagName, 'P');
				equal(node.nextSibling.id, 'last');
				start();
			}, editor.selection.getNode());
		}, editor.selection.getNode());
	}, editor.selection.getNode());
});


asyncTest('Outdent on enter when setting is set', function() {
	editor.settings.list_outdent_on_enter = true;
	editor.setContent("<ol><li>a<ol><li>b</li><li></li></ol></li></ol>");
	setSelection('li ol li:nth-child(2)', 0);
	robot.type(ENTER, false, function(){
		equal(editor.getContent(), "<ol><li>a<ol><li>b</li></ol></li><li></li></ol>");
		start();
	}, editor.selection.getNode());
});

asyncTest('Outdent in nested list on enter when setting is set', function() {
	editor.settings.list_outdent_on_enter = true;
	editor.setContent("<ol><li>a<ol><li>b</li><li></li></ol></li></ol>");
	setSelection('li ol li:nth-child(2)', 0);
	robot.type(ENTER, false, function() {
		robot.type(ENTER, false, function() {
			robot.type('a', false, function(){
				equal(editor.getContent(), "<ol><li>a<ol><li>b</li></ol></li></ol><p>a</p>");
				start();
			}, editor.selection.getNode());
		}, editor.selection.getNode());
	}, editor.selection.getNode());
});

// Removed since the EnterKey.js logic seems to solve this
/*
function testNestedListHasZeroSizedNbsp() {
	robot.type(ENTER, false, function() {
		var ul = editor.dom.select('#u')[0];
		var text = ul.parentNode.childNodes[0].nodeValue;
		equal(text, ZERO_SIZED_NBSP);
		start();
	}, editor.selection.getNode());
}

asyncTest('Nested list has zero-sized nbsp in Gecko & IE8', function() {
	if (!(tinymce.isGecko || tinymce.isIE8)) {
		start();
		ok(true, "Skupped");
	} else {
		editor.settings.list_outdent_on_enter = true;
		editor.setContent("<ul><li>a<ul id='u'><li>b</li></ul></li></ul>");
		setSelection('li', 1);

		if (tinymce.isIE8) {
			// IE8 places the caret on the nested list item so we press left to get to end of first list item
			robot.type(LEFT, false, testNestedListHasZeroSizedNbsp, editor.selection.getNode());
		} else {
			testNestedListHasZeroSizedNbsp();
		}
	}
});
*/

asyncTest('Outdent from sublist using shift-tab keys', function() {
	editor.setContent("<ul><li>a<ul><li>b</li></ul></li></ul>");
	setSelection('li ul li', 0);
	robot.type(TAB, true, function(){
		equal(editor.getContent(), "<ul><li>a</li><li>b</li></ul>");
		start();
	}, editor.selection.getNode());
});

asyncTest('Caret positioned correctly after escaping list and applying formatting ', function() {
	// Don't run this test on Firefox as there is a bug outdenting list items and this will fail the test.
	// When we have outdented from a sub list item to the outmost level no marker is shown and we can't exit the list by
	// pressing enter. Pressing enter correctly exists the list.
	if (tinymce.isGecko) {
		ok(true, "Skipped");
		start();
	} else {
		editor.settings.list_outdent_on_enter = true;
		editor.setContent("<ul><li>a<ul><li>b</li></ul></li></ul>");
		setSelection('li ul li', 1);
		robot.type(ENTER, false, function() {
			robot.type(ENTER, false, function() {
				robot.type(ENTER, false, function() {
					editor.execCommand('FormatBlock', false, 'h1');
					var node = editor.selection.getNode();
					var list = editor.dom.getParent(node, 'ol,ul');
					ok(list === null, "selection must be outside of list");
					start();
				}, editor.selection.getNode());
			}, editor.selection.getNode());
		}, editor.selection.getNode());
	}
});

asyncTest('Deleting text-node from start of list', function() {
	editor.setContent("<ul><li>a</li><li>b</li></ul>");
	setSelection('li', 1);
	robot.type(BACKSPACE, false, function() {
		equal(editor.getContent(), "<ul><li></li><li>b</li></ul>");
		start();
	}, editor.selection.getNode());
});

asyncTest('Deleting bullet from start of list', function() {
	editor.setContent("<ul><li>a</li><li>b</li></ul>");
	setSelection('li', 0);
	robot.type(BACKSPACE, false, function() {
		equal(editor.getContent(), "<p>a</p><ul><li>b</li></ul>");
		start();
	}, editor.selection.getNode());
});

asyncTest('Deleting bullet from start of list outdents inner lists items', function() {
	editor.setContent("<p>a</p><ul><li>b<ul><li>c</li><li>d</li></ul></li></ul>");
	setSelection('li', 0);
	robot.type(BACKSPACE, false, function() {
		equal(editor.getContent(), "<p>a</p><p>b</p><ul><li>c</li><li>d</li></ul>");
		start();
	}, editor.selection.getNode());
});

asyncTest('Deleting empty li with nested list is deleted in Webkit', function(){
	if (!tinymce.isWebKit) {
		ok(true, "Skipped");
		start();
	} else {
		editor.setContent("<ol id='a'><li>a</li><li id='b'>a<br /><ul><li>b</li><li>c</li></ul></li></ol>");
		setSelection('#b', 0);
		editor.focus();
		robot.type(BACKSPACE, false, function() {
			equal(editor.dom.select('ol ul li').length, 2);
			var olLis = tinymce.grep(editor.dom.get('a').childNodes, function(n) {
				return n.nodeName == 'LI'
			});
			equal(olLis.length, 1);
			start();
		}, editor.selection.getNode());
	}
});

asyncTest('Creates new list item without surrounding element when caret at end of list item', function(){
	function testCreateNewList(el) {
		queue.add(function() {
			var listItemContent = '<' + el + '>something</' + el + '>';
			editor.setContent('<ul><li>' + listItemContent + '</li></ul>');
			setSelection(el, 9);
			editor.focus();
			robot.type(ENTER, false, function() {
				var rng = editor.selection.getRng(true);
				var li = editor.dom.getParent(editor.selection.getStart(), 'li');
				equal(editor.getContent(), '<ul><li>' + listItemContent + '</li><li></li></ul>');
				queue.next();
			});
		});
	}

	var queue  = new dsl.Queue();
	tinymce.map('h1,h2,h3,h4,h5,h6,p,div'.split(','), testCreateNewList);
	queue.done();
});

asyncTest('Select the entire document, and apply and remove ordered list', function() {
  editor.setContent("<p>a</p><p>b</p>");
  editor.focus();
  robot.typeAsShortcut('a', function() {
	  editor.execCommand('InsertOrderedList');
	  editor.execCommand('InsertOrderedList');
	  equal(editor.getContent(), "<p>a</p><p>b</p>");
	  start();
  });
});

asyncTest('Select the entire document, and apply and remove unordered list', function() {
  editor.setContent("<p>a</p><p>b</p>");
  editor.focus();
  robot.typeAsShortcut('a', function() {
	  editor.execCommand('InsertUnorderedList');
	  editor.execCommand('InsertUnorderedList');
	  equal(editor.getContent(), "<p>a</p><p>b</p>");
	  start();
  });
});

var initTinyFunction = function(){
	tinyMCE.init({
		mode : "exact",
		elements : "elm1",
		theme : "advanced",
		cleanup: true,
		// Turn this off because we want the list actions to create the right DOM structure from the start.
		fix_list_elements: false,
		plugins : 'lists',
		add_unload_trigger : false,
		apply_source_formatting : 0,
		init_instance_callback : function(ed) {
			editor = ed;

			ed.onNodeChange.addToTop(function() {
				return false;
			});
		}
	});
}
</script>
</head>
<body>
	<h1 id="qunit-header">List General Tests</h1>
	<h2 id="qunit-banner"></h2>
	<div id="qunit-testrunner-toolbar"></div>
	<h2 id="qunit-userAgent"></h2>
	<ol id="qunit-tests"></ol>
	<div id="content">
		<textarea id="elm1" name="elm1"></textarea>
	</div>
	<script type="text/javascript" language="JavaScript" src="jsrobot/robot.js"></script>
	<script>
		initWhenTinyAndRobotAreReady(initTinyFunction);
	</script>
</body>
</html>
